﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CADTool
{
    public static class CustomMethod
    {
        /// <summary>
        /// 单行阵列实体的方法
        /// </summary>
        /// <param name="ent">实体</param>
        /// <param name="vec">向量</param>
        /// <param name="num">复制个数</param>
        public static void CopyAndOffset(this Entity ent, Vector3d vec, int num)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                for (int i = 1; i < num + 1; i++)
                {
                    Vector3d tempvec = vec * i;
                    Matrix3d mt = Matrix3d.Displacement(tempvec);

                    Entity tempEntity = ent.GetTransformedCopy(mt);
                    btr.AppendEntity(tempEntity);
                    trans.AddNewlyCreatedDBObject(tempEntity, true);
                }
                trans.Commit();
            }
        }
        /// <summary>
        /// 通过计算圆弧参数的方式三点绘弧
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        public static void AddCirToModelSpace1(Point2d p1, Point2d p2, Point2d p3)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                CircularArc2d cArc = new CircularArc2d(p1, p2, p3);
                Arc arc = new Arc(ToPoint3d(cArc.Center), cArc.Radius, GetAngleToXaxis(ToPoint3d(cArc.Center), ToPoint3d(p1)), GetAngleToXaxis(ToPoint3d(cArc.Center), ToPoint3d(p3)));
                btr.AppendEntity(arc);
                trans.AddNewlyCreatedDBObject(arc, true);
                trans.Commit();
            }
        }
        /// <summary>
        /// 用发送命令的方式三点绘制圆弧
        /// </summary>
        /// <param name="p1">圆弧起点</param>
        /// <param name="p2">圆弧中点</param>
        /// <param name="p3">圆弧终点</param>
        public static void AddCirToModelSpace(Point2d p1, Point2d p2, Point2d p3)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            string cmdString = "_pl ";
            cmdString += $"{p1.X},{p1.Y} ";
            cmdString += "A ";
            cmdString += "S ";
            cmdString += $"{p2.X},{p2.Y} ";
            cmdString += $"{p3.X},{p3.Y} ";
            cmdString += " ";
            doc.SendStringToExecute(cmdString, true, false, false);

        }
        /// <summary>
        /// 获取两点成直线到X轴之间的角度（有正负）
        /// </summary>
        /// <param name="startPoint">起点</param>
        /// <param name="endPoint">终点</param>
        /// <returns></returns>
        public static double GetAngleToXaxis(Point3d startPoint, Point3d endPoint)
        {
            //声明一个与X轴平行的向量
            Vector3d temp = new Vector3d(1, 0, 0);
            //获取起点到终点的向量
            Vector3d VsToe = startPoint.GetVectorTo(endPoint);
            return VsToe.Y > 0 ? temp.GetAngleTo(VsToe) : -temp.GetAngleTo(VsToe);
        }
        /// <summary>
        /// 将二维点转为三维
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static Point3d ToPoint3d(Point2d p)
        {
            return new Point3d(p.X, p.Y, 0);
        }
        /// <summary>
        /// 将三维点转换为二维点
        /// </summary>
        /// <param name="p3"></param>
        /// <returns></returns>
        public static Point2d ToPoint2d(this Point3d p3)
        {
            Point2d pt = new Point2d(p3.X, p3.Y);
            return pt;
        }
        /// <summary>
        /// 通过两点向数据库添加一条多段线
        /// </summary>
        /// <param name="p1">多段线的第一点</param>
        /// <param name="p2">多段线的第二点</param>
        /// <returns></returns>
        public static Entity AddLineToModelSpace(Point2d p1, Point2d p2)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Polyline pl = new Polyline();
            pl.AddVertexAt(0, p1, 0, 0, 0);
            pl.AddVertexAt(1, p2, 0, 0, 0);
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                ObjectId id = btr.AppendEntity(pl);
                Entity ent = (Entity)id.GetObject(OpenMode.ForRead);
                trans.AddNewlyCreatedDBObject(pl, true);
                trans.Commit();
                return ent;
            }
        }
        /// <summary>
        /// CAD打开文件对话框
        /// </summary>
        /// <param name="message">对话框标题</param>
        /// <returns></returns>
        public static string FileNameForOpen(string message)
        {
            Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
            PromptFileNameResult i = ed.GetFileNameForOpen(message);
            if (i.Status == PromptStatus.OK)
            {
                return i.StringResult;
            }
            else
            {
                return "";
            }
        }
        /// <summary>
        /// 偏移直线上的中点
        /// </summary>
        /// <param name="point1">线段起点</param>
        /// <param name="point2">线段中点</param>
        /// <param name="offset">偏移距离</param>
        /// <returns>返回线段中点垂直方向的偏移点</returns>
        public static List<Point3d> PointOffset(Point3d point1, Point3d point2, double offset)
        {
            Line line = new Line(point1, point2);
            List<Point3d> returnList = new List<Point3d>();
            DBObjectCollection offsetLine = new DBObjectCollection();
            try
            {
                offsetLine = line.GetOffsetCurves(offset);
            }
            catch
            {
                offsetLine.Add(new Line(point1, point2));
            }
            if (offsetLine.Count == 1)
            {
                Line oLine = offsetLine[0] as Line;
                returnList.Add(oLine.StartPoint);
                returnList.Add(new LineSegment3d(oLine.StartPoint, oLine.EndPoint).MidPoint);
                returnList.Add(oLine.EndPoint);
                line.Dispose();
                oLine.Dispose();
                return returnList;
            }
            else
            {
                line.Dispose();
                return null;
            }
        }
        /// <summary>
        /// 获取两点之间的距离
        /// </summary>
        /// <param name="point1">第一点的坐标</param>
        /// <param name="point2">第二点的坐标</param>
        /// <returns>两点之间的距离</returns>
        public static double GetDistanceBetweenTowPoint(Point3d point1, Point3d point2)
        {
            return Math.Sqrt(Math.Pow((point1.X - point2.X), 2) + Math.Pow((point1.Y - point2.Y), 2));
        }
        /// <summary>
        /// 获取点
        /// </summary>
        /// <param name="ppo">message</param>
        /// <returns></returns>
        public static PromptPointResult GetPoint(PromptPointOptions ppo)
        {
            ppo.AllowNone = true;
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            return ed.GetPoint(ppo);
        }
        /// <summary>
        /// 返回与之距离最近的点
        /// </summary>
        /// <param name="p"></param>
        /// <param name="pts"></param>
        /// <returns></returns>
        public static Point3d Nearset(this Point3d p, List<Point3d> pts)
        {
            double dis = 0;
            double temp = 100;
            Point3d tempPoint = new Point3d();
            foreach (Point3d item in pts)
            {
                dis = p.DistanceTo(item);
                if (dis < temp)
                {
                    temp = dis;
                    tempPoint = item;
                }
            }
            return tempPoint;
        }
        /// <summary>
        /// 将单个图形对象添加到图形文件中
        /// </summary>
        /// <param name="db">图形数据库</param>
        /// <param name="ent">图形对象</param>
        /// <returns>图形的ObjectId对象</returns>
        public static ObjectId AddEntityToModelSpace(this Database db, Entity ent)
        {
            //声明Object用于返回
            ObjectId entId = ObjectId.Null;
            //开启事务处理
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                //打开块表记录
                BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                //打开块表记录
                BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                //添加图形到块表记录  
                entId = btr.AppendEntity(ent);
                //更新数据信息
                trans.AddNewlyCreatedDBObject(ent, true);
                //提交事务
                trans.Commit();
            }
            return entId;
        }
        /// <summary>
        /// 将多个或一个图形添加到图形文件中
        /// </summary>
        /// <param name="db">图形数据库</param>
        /// <param name="ents">图形实体</param>
        /// <returns>ObjectId[]</returns>
        public static ObjectId[] AddEntityToModelSpace(this Database db, params Entity[] ents)
        {
            ObjectId[] ids = new ObjectId[ents.Length];
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {

                BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                for (int i = 0; i < ents.Length; i++)
                {
                    ids[i] = btr.AppendEntity(ents[i]);
                    trans.AddNewlyCreatedDBObject(ents[i], true);
                }
                trans.Commit();

            }
            return ids;
        }
        /// <summary>
        /// 将多个图形对象添加到图形文件中
        /// </summary>
        /// <param name="db">图形数据库</param>
        /// <param name="ents">图形对象</param>
        /// <returns>ObjectId</returns>
        public static ObjectId[] AddEntityToModelSpace(this Database db, List<Entity> ents)
        {
            ObjectId[] ids = new ObjectId[ents.Count];
            //开启事务处理
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                //打开块表记录
                BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                //打开块表记录
                BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                //添加图形到块表记录  
                for (int i = 0; i < ents.Count; i++)
                {
                    ids[i] = btr.AppendEntity(ents[i]);
                    //更新数据信息
                    trans.AddNewlyCreatedDBObject(ents[i], true);
                }
                trans.Commit();
            }
            return ids;
        }
        /// <summary>
        /// 将实体添加到数据库中
        /// </summary>
        /// <param name="ents">实体</param>
        public static void AddEntities(List<Entity> ents)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord btr = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                foreach (var item in ents)
                {
                    btr.AppendEntity(item);
                    trans.AddNewlyCreatedDBObject(item, true);
                }

                trans.Commit();
            }
        }
        /// <summary>
        /// 添加点到图形数据库
        /// </summary>
        /// <param name="dBPoints">DBPoint</param>
        public static void AddPointToModelSpace(List<DBPoint> dBPoints)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord btr = trans.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite) as BlockTableRecord;
                foreach (var item in dBPoints)
                {
                    btr.AppendEntity(item);
                    trans.AddNewlyCreatedDBObject(item, true);
                }
                trans.Commit();
            }
        }
        /// <summary>
        /// 获取实体集合
        /// </summary>
        /// <returns>List<Entity></returns>
        public static List<Entity> SelectEntitys()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            //获取PickFirst 选择集
            PromptSelectionResult psr;
            SelectionSet sSt;
            //清空PickFirst选择集
            ObjectId[] idarryEmpty = new ObjectId[0];
            try
            {
                ed.SetImpliedSelection(idarryEmpty);
            }
            catch (Exception)
            {
                ed.WriteMessage("没有按照计划操作......");
            }

            //请求从图形区域选择对象
            psr = ed.GetSelection();
            //如果提示状态OK，表示已选择对象
            if (psr.Status == PromptStatus.Cancel) return null;
            if (psr.Status == PromptStatus.OK)
            {
                sSt = psr.Value;
                List<Entity> ents = new List<Entity>();
                using (Transaction trans = db.TransactionManager.StartTransaction())
                {
                    foreach (SelectedObject item in sSt)
                    {
                        Entity ent = (Entity)trans.GetObject(item.ObjectId, OpenMode.ForRead);
                        ents.Add(ent);
                    }
                }
                return ents;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 添加直线到图形中
        /// </summary>
        /// <param name="db">图形数据库</param>
        /// <param name="startPoint">起点</param>
        /// <param name="endPoint">终点</param>
        /// <returns></returns>
        public static ObjectId AddLineToModelSpace(this Database db, Point3d startPoint, Point3d endPoint)
        {
            Line line = new Line(startPoint, endPoint);
            return db.AddEntityToModelSpace(new Line(startPoint, endPoint));
        }
        /// <summary>
        /// 获取实体集合的包围盒子
        /// </summary>
        /// <param name="ents">实体集合</param>
        /// <returns>包围盒子的左下和右上的坐标</returns>
        public static Tuple<Point3d, Point3d> GetBoxPoint(List<Entity> ents)
        {
            double minx = ents.Min(x => x.Bounds.Value.MinPoint.X);
            double miny = ents.Min(x => x.Bounds.Value.MinPoint.Y);
            double maxx = ents.Max(x => x.Bounds.Value.MaxPoint.X);
            double maxy = ents.Max(x => x.Bounds.Value.MaxPoint.Y);
            Tuple<Point3d, Point3d> tuple = new Tuple<Point3d, Point3d>(new Point3d(minx, miny, 0), new Point3d(maxx, maxy, 0));
            return tuple;
        }
        /// <summary>
        /// 由插入点、文字内容、文字样式、文字高度创建单行文字
        /// </summary>
        /// <param name="textString"></param>
        /// <param name="position"></param>
        /// <param name="height"></param>
        /// <param name="rot"></param>
        /// <param name="isfield"></param>
        /// <returns></returns>
        public static DBText DbText(string textString, Point3d position, double height, double rot, bool isfield)
        {
            DBText txt = new DBText();
            txt.Position = position;
            txt.Height = height;
            txt.Rotation = rot;
            if (isfield)
            {
                Field field = new Field(textString);
                txt.SetField(field);
            }
            else
            {
                txt.TextString = textString;
            }
            return txt;
        }
        /// <summary>
        /// 提示用户拾取点
        /// </summary>
        /// <param name="message">提示</param>
        /// <returns>返回Point3d</returns>
        public static Point3d GetPoint(string message)
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptPointResult pt = ed.GetPoint(message);
            if (pt.Status == PromptStatus.OK)
            {
                return pt.Value;
            }
            else
            {
                return new Point3d();
            }
        }
        /// <summary>
        /// 关闭layerName层
        /// </summary>
        /// <param name="layerName">图层名称</param>
        public static void CloseThisLayer(this string layerName)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                LayerTable lt = trans.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                if (lt.Has(layerName))
                {
                    LayerTableRecord ltr = lt[layerName].GetObject(OpenMode.ForWrite) as LayerTableRecord;
                    ltr.IsOff = true;
                }
                trans.Commit();
            }
        }
        /// <summary>
        /// 关闭layer之外的图层
        /// </summary>
        /// <param name="layer">图层名称</param>
        public static void CloseBesidesLayeres(this string layer)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                //打开层表
                LayerTable lt = trans.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
                foreach (ObjectId item in lt)
                {
                    LayerTableRecord ltr = item.GetObject(OpenMode.ForWrite) as LayerTableRecord;
                    if (layer != ltr.Name)
                    {
                        if (!ltr.IsOff)
                        {
                            ltr.IsOff = true;
                        }
                        else continue;
                    }
                }
                trans.Commit();
            }
        }
        /// <summary>
        /// 获取实体的层名
        /// </summary>
        /// <param name="ent">图形实体</param>
        /// <returns>返回实体图层名称</returns>
        public static string GetLayerName(this Entity ent)
        {
            string layerName;
            Database db = HostApplicationServices.WorkingDatabase;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                trans.GetObject(ent.Id, OpenMode.ForRead);
                layerName = ent.Layer;
            }
            return layerName;
        }

        /// <summary>
        /// 获得当前图形中的所有的图层
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        public static List<LayerTableRecord> GetAllLayers(this Database db)
        {
            //打开层表
            LayerTable lt = (LayerTable)db.LayerTableId.GetObject(OpenMode.ForRead);
            //用于返回层表记录的列表
            List<LayerTableRecord> ltrs = new List<LayerTableRecord>();
            foreach (ObjectId id in lt)
            {
                //打开层表记录
                LayerTableRecord lrt = (LayerTableRecord)id.GetObject(OpenMode.ForRead);
                ltrs.Add(lrt); //添加到返回列表中
            }
            return ltrs;
        }
        /// <summary>
        /// 向CAD发送命令
        /// </summary>
        /// <param name="command">命令字符串</param>
        public static void SendCommand(string command)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Document doc = Application.DocumentManager.MdiActiveDocument;
            doc.SendStringToExecute(command + " ", true, false, false);
        }
        /// <summary>
        /// 让CAD获得焦点
        /// </summary>
        public static void GetFocus()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            doc.Window.Focus();
        }
        /// <summary>
        /// 创建多段线
        /// </summary>
        /// <param name="pts">二维点集合</param>
        /// <param name="width">线宽</param>
        /// <returns>二维多段线</returns>
        public static Polyline Polyline(Point2dCollection pts, double width)
        {
            try
            {
                Polyline ent = new Polyline();
                for (int i = 0; i < pts.Count; i++)
                {
                    ent.AddVertexAt(i, pts[i], 0, width, width);
                }
                return ent;
            }
            catch (System.Exception)
            {
                return new Polyline();
            }
        }
        /// <summary>
        /// 由插入点、文字内容、文字高度、文字宽度创建多行文字
        /// </summary>
        /// <param name="textString">文字内容</param>
        /// <param name="location">基点</param>
        /// <param name="height">文字高度</param>
        /// <param name="width">宽度</param>
        /// <param name="rot">文字转角</param>
        /// <param name="isfield">是否包含域</param>
        /// <returns></returns>
        public static MText MText(string textString, Point3d location, double height, double width, double rot, bool isfield)
        {
            MText mtxt = new MText();
            mtxt.Location = location;
            mtxt.Height = height;
            mtxt.Width = width;
            mtxt.Rotation = rot;
            if (isfield)
            {
                Field field = new Field(textString);
                mtxt.SetField(field);
            }
            else
            {
                mtxt.Contents = textString;
            }
            return mtxt;
        }
        /// <summary>
        /// 改变绘图次序到底层
        /// </summary>
        /// <param name="ent"></param>
        /// <param name="db"></param>
        public static void MoveBottom(Entity ent, Database db)
        {
            if (ent == null) return;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                ObjectIdCollection idc = new ObjectIdCollection();
                idc.Add(ent.ObjectId);
                BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForWrite, false);
                BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false);
                DrawOrderTable orderTable = trans.GetObject(btr.DrawOrderTableId, OpenMode.ForWrite) as DrawOrderTable;
                orderTable.MoveToBottom(idc);
                trans.Commit();
            }
        }
        /// <summary>
        /// 改变绘图次序到顶层
        /// </summary>
        /// <param name="ent"></param>
        /// <param name="db"></param>
        public static void MoveTop(Entity ent, Database db)
        {
            if (ent == null) return;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                ObjectIdCollection idc = new ObjectIdCollection();
                idc.Add(ent.ObjectId);
                BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForWrite, false);
                BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false);
                DrawOrderTable orderTable = trans.GetObject(btr.DrawOrderTableId, OpenMode.ForWrite) as DrawOrderTable;
                orderTable.MoveToTop(idc);
            }
        }
        /// <summary>
        /// 判断两个实体是否相交
        /// </summary>
        /// <param name="ent1">实体1</param>
        /// <param name="ent2">实体2</param>
        /// <returns></returns>
        public static bool ExtentsIntersect(this Entity ent1, Entity ent2)
        {
            Point3dCollection point3dCollection = new Point3dCollection();
            ent1.BoundingBoxIntersectWith(ent2, Intersect.OnBothOperands, point3dCollection, IntPtr.Zero, IntPtr.Zero);
            if (point3dCollection.Count != 0)
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 判断两个包围盒子是否发生碰撞
        /// </summary>
        /// <param name="ext1">包围盒子1</param>
        /// <param name="ext2">包围盒子2</param>
        /// <returns>bool</returns>
        public static bool ExtensHit(this Extents3d ext1, Extents3d ext2)
        {
            double AXmin = ext1.MinPoint.X; double AYmin = ext1.MinPoint.Y;
            double AXmax = ext1.MaxPoint.X; double AYmax = ext1.MaxPoint.Y;
            double BXmin = ext2.MinPoint.X; double BYmin = ext2.MinPoint.Y;
            double BXmax = ext2.MaxPoint.X; double BYmax = ext2.MaxPoint.Y;
            bool b1 = AXmax >= BXmin && AXmin <= BXmax && AYmax >= BYmin && AYmin <= BYmax;
            bool b2 = BXmax >= AXmin && BXmin <= AXmax && BYmax >= AYmin && BYmin <= AYmax;
            return b1 || b2;
        }
        /// <summary>
        /// 用多段线绘制包围盒子
        /// </summary>
        /// <param name="ext">范围</param>
        /// <returns>Polyline</returns>
        public static Polyline ExtentsPolyline(this Extents3d ext)
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Point2d p1 = new Point2d(ext.MinPoint.X, ext.MinPoint.Y);
            Point2d p2 = new Point2d(ext.MinPoint.X, ext.MaxPoint.Y);
            Point2d p3 = new Point2d(ext.MaxPoint.X, ext.MaxPoint.Y);
            Point2d p4 = new Point2d(ext.MaxPoint.X, ext.MinPoint.Y);
            Polyline pLine = new Polyline();
            pLine.AddVertexAt(0, p1, 0, 0, 0);
            pLine.AddVertexAt(1, p2, 0, 0, 0);
            pLine.AddVertexAt(2, p3, 0, 0, 0);
            pLine.AddVertexAt(3, p4, 0, 0, 0);
            pLine.Closed = true;
            return pLine;
        }
        /// <summary>
        /// 单行文字纵向对齐
        /// </summary>
        /// <param name="textList">文字List</param>
        public static void AlignTextVertically(List<DBText> textList)
        {
            if (textList.Count == 0) return;
            using (Transaction trans = Z.db.TransactionManager.StartTransaction())
            {
                Point3d position = textList[0].Position;
                for (int i = 0; i < textList.Count; i++)
                {
                    Vector3d moveVector = new Vector3d(0, -textList[i].Height * i * 2.0, 0);
                    trans.GetObject(textList[i].ObjectId, OpenMode.ForWrite);
                    textList[i].Position = position + moveVector;
                }
                trans.Commit();
            }

        }
        /// <summary>
        /// 单行文字横对齐
        /// </summary>
        /// <param name="textList">文字List</param>
        public static void AlignTextHorizontal(List<DBText> textList)
        {
            DocumentLock documentLock = Z.doc.LockDocument();
            if (textList.Count < 2) return;
            List<Point3d> maxPts = new List<Point3d>();
            List<Point3d> minPts = new List<Point3d>();
            foreach (DBText txt in textList)
            {
                maxPts.Add(new Point3d(txt.Bounds.Value.MaxPoint.X, txt.Bounds.Value.MaxPoint.Y, 0));
                minPts.Add(new Point3d(txt.Bounds.Value.MinPoint.X, txt.Bounds.Value.MinPoint.Y, 0));
            }
            using (Transaction trans = Z.db.TransactionManager.StartTransaction())
            {
                Point3d position = textList[0].Position;
                double dist = 0;
                for (int i = 1; i < textList.Count; i++)
                {
                    dist += maxPts[i - 1].X - minPts[i - 1].X;
                    Vector3d moveVector = new Vector3d(dist, 0, 0);
                    trans.GetObject(textList[i].ObjectId, OpenMode.ForWrite);
                    textList[i].Position = position + moveVector;
                }
                trans.Commit();
            }
            documentLock.Dispose();
        }
        /// <summary>
        /// 改变实体颜色
        /// </summary>
        /// <param name="id">ObjectId</param>
        /// <param name="index">ColorIndex</param>0,
        public static void ChangeColor(this ObjectId id, byte index)
        {
            Database db = Application.DocumentManager.MdiActiveDocument.Database;
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                var dbobject = trans.GetObject(id, OpenMode.ForWrite);
                if (dbobject is Entity ent)
                {
                    ent.ColorIndex = index;
                }
                trans.Commit();
            }
        }
        /// <summary>
        /// 创建块并添加到数据库中
        /// </summary>
        /// <param name="db">图形数据库</param>
        /// <param name="blockName">块名</param>
        /// <param name="ents">Entity</param>
        /// <returns>ObjectId</returns>
        public static ObjectId AddBlockTableRecord(this Database db, string blockName, List<Entity> ents)
        {
            //打开块表
            BlockTable bt = db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
            if (!bt.Has(blockName)) //判断是否存在名为blockName的块
            {
                //创建一个BlockTableRecord类的对象，表示所要创建的块
                BlockTableRecord btr = new BlockTableRecord();
                btr.Name = blockName;    //设置快名字
                //将列表中的实体加入到新建的BlockTableRecord对象
                ents.ForEach(ent => btr.AppendEntity(ent));
                bt.UpgradeOpen();
                bt.Add(btr);
                db.TransactionManager.AddNewlyCreatedDBObject(btr, true);
                bt.DowngradeOpen();
            }
            return bt[blockName];
        }
        /// <summary>
        /// id是否有效，未被删除
        /// </summary>
        /// <param name="id">对象id</param>
        /// <returns>id有效返回 <see langword="true"/>，反之返回 <see langword="false"/></returns>
        public static bool IsOK(this ObjectId id)
        {
            return !id.IsNull && !id.IsValid && !id.IsEffectivelyErased && id.IsResident;
        }
        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="ents"></param>
        public static void EraseEntities(List<Entity> ents)
        {
            using (Transaction trans = Z.db.TransactionManager.StartTransaction())
            {
                foreach (var item in ents)
                {
                    trans.GetObject(item.Id, OpenMode.ForWrite);
                    item.Erase();
                }
                trans.Commit();
            }
        }
        /// <summary>
        /// 获取用户输入的小数
        /// </summary>
        /// <param name="message">提示词</param>
        /// <param name="d">传出的小数</param>
        /// <returns>bool</returns>
        public static bool GetDouble(string message, out double d)
        {
            d = 0;
            Editor editor = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptDoubleResult pdr = editor.GetDouble(message);
            if (pdr.Status == PromptStatus.OK)
            {
                d = pdr.Value;
                return true;
            }
            return false;
        }
        #region 实体线性变换
        /// <summary>
        /// 移动实体
        /// </summary>
        /// <param name="ent">实体</param>
        /// <param name="form">基点</param>
        /// <param name="to">目标点</param>
        public static void Move(this Entity ent, Point3d form, Point3d to)
        {
            ent.TransformBy(Matrix3d.Displacement(to - form));
        }
        #endregion
        #region 图形扩展类
        /// <summary>
        /// ucs到wcs的点变换
        /// </summary>
        /// <param name="point">点</param>
        /// <returns>变换后的点</returns>
        public static Point3d Ucs2Wcs(this Point3d point)
        {
            return point.TransformBy(Application.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem);
        }
        /// <summary>
        /// wcs到ucs的点的变换
        /// </summary>
        /// <param name="point">点</param>
        /// <returns>变换后的点</returns>
        public static Point3d Wcs2Ucs(this Point3d point)
        {
            return point.TransformBy(Application.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem);
        }
        #endregion
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mText"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static List<Point3d> GetBestBoxPoints(this MText mText)
        {
            var width = mText.ActualWidth;
            var height = mText.ActualHeight;
            var location = mText.Location;
            Point3d? corner1 = null;
            switch (mText.Attachment)
            {
                case AttachmentPoint.TopLeft:
                    corner1 = location + new Vector3d(0, -height, 0);
                    break;
                case AttachmentPoint.TopCenter:
                    corner1 = location + new Vector3d(-width * 0.5, -height, 0);
                    break;
                case AttachmentPoint.TopRight:
                    corner1 = location + new Vector3d(-width, -height, 0);
                    break;
                case AttachmentPoint.MiddleLeft:
                    corner1 = location + new Vector3d(width * 0.5, -height * 0.5, 0);
                    break;
                case AttachmentPoint.MiddleRight:
                    corner1 = location + new Vector3d(-width, -height, 0);
                    break;
                case AttachmentPoint.BottomLeft:
                    corner1 = location;
                    break;
                case AttachmentPoint.BottomCenter:
                    corner1 = location + new Vector3d(-width * 0.5, 0, 0);
                    break;
                case AttachmentPoint.BottomRight:
                    corner1 = location + new Vector3d(-width, -0, 0);
                    break;
            }
            if (corner1 is null)
                throw new Exception("\nMText获取Box错误");
            var corner2 = corner1.Value + new Vector3d(width,height,0);
            var mt3d = Matrix3d.Rotation(mText.Rotation,Vector3d.ZAxis,location);
            return corner1.Value.GetRecPoint3ds(corner2).Select(pt=>pt.TransformBy(mt3d)).ToList();
        }
        /// <summary>
        /// 由矩形得左下角点和右上角点计算四点坐标
        /// </summary>
        /// <param name="corner1">矩形得左下角点</param>
        /// <param name="corner3">矩形得右上角点</param>
        /// <returns>返回矩形得四个顶点</returns>
        public static List<Point3d> GetRecPoint3ds(this Point3d corner1,Point3d corner3)
        {
            List<Point3d> p3ds= new List<Point3d>();
            Point3d corner2 = new Point3d(corner3.X,corner1.Y,0);
            Point3d corner4 = new Point3d(corner1.X,corner3.Y,0);
            p3ds.Add(corner1);
            p3ds.Add(corner2);
            p3ds.Add(corner3);
            p3ds.Add(corner4);
            return p3ds;        
        }
        public static void DrawPolyLine(this List<Point3d> p3ds)
        {
            Polyline pl=new Polyline();
            for (int i = 0; i < p3ds.Count; i++)
            {
                pl.AddVertexAt(i, p3ds[i].Convert2d(new Plane()),0,0,0);
            }
            pl.Closed = true;
            AddEntities(new List<Entity> { pl});
        }

         


    }
}